﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.UI.WebControls;

namespace TaskManager.Web.Extensions
{
    /// <summary>
    /// Razor extensions
    /// </summary>
    public static class HtmlHelperExtensions
    {
        /// <summary>
        /// Returns HTML markup to show Name and Value
        /// </summary>
        /// <typeparam name="TModel">Type of the model</typeparam>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="name">Name</param>
        /// <param name="value">Value</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString NameAndValue<TModel>(this HtmlHelper<TModel> htmlHelper, string name, string value)
        {
            MvcHtmlString nameHtml = htmlHelper.Label(name);

            var tagBuilder = new TagBuilder("span");
            tagBuilder.AddCssClass("value");
            tagBuilder.SetInnerText(value);

            var valueHtml = new MvcHtmlString(tagBuilder.ToString());

            return htmlHelper.Partial("_NameAndValue", new Tuple<MvcHtmlString, MvcHtmlString>(nameHtml, valueHtml));
        }

        /// <summary>
        /// Returns HTML markup to show Name and Text Box
        /// </summary>
        /// <typeparam name="TModel">Type of the model</typeparam>
        /// <typeparam name="TValue">Type of the value</typeparam>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="name">Name</param>
        /// <param name="valueExpression">the object that contains the properties to render</param>
        /// <param name="htmlAttributes">An object that contains HTML attributes to set for element</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString NameAndTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, string name, 
            Expression<Func<TModel, TValue>> valueExpression, object htmlAttributes)
        {
            MvcHtmlString labelHtml = htmlHelper.Label(name);
            MvcHtmlString textBoxHtml = htmlHelper.TextBoxFor(valueExpression, htmlAttributes);
            MvcHtmlString validationMsgHtml = htmlHelper.ValidationMessageFor(valueExpression, null, new {@class = "help-inline"});

            return htmlHelper.Partial("_NameAndInput", new Tuple<MvcHtmlString,MvcHtmlString,MvcHtmlString>(labelHtml, textBoxHtml, validationMsgHtml));
        }

        /// <summary>
        /// Returns HTML markup to show Name and Checkbox
        /// </summary>
        /// <typeparam name="TModel">Type of the model</typeparam>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="name">Name</param>
        /// <param name="valueExpression">the object that contains the properties to render</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString NameAndCheckboxFor<TModel>(this HtmlHelper<TModel> htmlHelper, string name, Expression<Func<TModel, bool>> valueExpression)
        {
            MvcHtmlString labelHtml = htmlHelper.Label(name);
            MvcHtmlString checkboxHtml = htmlHelper.CheckBoxFor(valueExpression, new {style="margin-top:10px;"});
            MvcHtmlString validationMsgHtml = htmlHelper.ValidationMessageFor(valueExpression, null, new { @class = "help-inline" });

            return htmlHelper.Partial("_NameAndInput", new Tuple<MvcHtmlString, MvcHtmlString, MvcHtmlString>(labelHtml, checkboxHtml, validationMsgHtml));
        }

        /// <summary>
        /// Returns HTML markup to show Name and Password input box
        /// </summary>
        /// <typeparam name="TModel">Type of the model</typeparam>
        /// <typeparam name="TValue">Type of the value</typeparam>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="name">Name</param>
        /// <param name="valueExpression">the object that contains the properties to render</param>
        /// <param name="htmlAttributes">An object that contains HTML attributes to set for element</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString NameAndPasswordFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, string name,
            Expression<Func<TModel, TValue>> valueExpression, object htmlAttributes)
        {
            MvcHtmlString labelHtml = htmlHelper.Label(name);
            MvcHtmlString passwordHtml = htmlHelper.PasswordFor(valueExpression, htmlAttributes);
            MvcHtmlString validationMsgHtml = htmlHelper.ValidationMessageFor(valueExpression, null, new { @class = "help-inline" });

            return htmlHelper.Partial("_NameAndInput", new Tuple<MvcHtmlString, MvcHtmlString, MvcHtmlString>(labelHtml, passwordHtml, validationMsgHtml));
        }

        /// <summary>
        /// Returns HTML markup to show Name and Text Area Box
        /// </summary>
        /// <typeparam name="TModel">Type of the model</typeparam>
        /// <typeparam name="TValue">Type of the value</typeparam>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="name">Name</param>
        /// <param name="valueExpression">The object that contains the properties to render</param>
        /// <param name="htmlAttributes">An object that contains HTML attributes to set for element</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString NameAndTextAreaFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, string name, 
            Expression<Func<TModel, TValue>> valueExpression, object htmlAttributes)
        {
            MvcHtmlString labelHtml = htmlHelper.Label(name);
            MvcHtmlString textBoxHtml = htmlHelper.TextAreaFor(valueExpression, htmlAttributes);
            MvcHtmlString validationMsgHtml = htmlHelper.ValidationMessageFor(valueExpression, null, new { @class = "help-inline" });

            return htmlHelper.Partial("_NameAndInput", new Tuple<MvcHtmlString, MvcHtmlString, MvcHtmlString>(labelHtml, textBoxHtml, validationMsgHtml));
        }

        /// <summary>
        /// Returns HTML markup to show Name and Drop Down List
        /// </summary>
        /// <typeparam name="TModel">Type of the model</typeparam>
        /// <typeparam name="TValue">Type of the value</typeparam>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="name">Name</param>
        /// <param name="valueExpression">The object that contains the properties to render</param>
        /// <param name="selectList">List of values</param>
        /// <param name="optionLabel">Selected value</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString NameAndDropDownListFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, string name, Expression<Func<TModel, TValue>> valueExpression,
            IEnumerable<SelectListItem> selectList, string optionLabel)
        {
            MvcHtmlString labelHtml = htmlHelper.Label(name);
            MvcHtmlString textBoxHtml = htmlHelper.DropDownListFor(valueExpression, selectList, optionLabel, new { @class = "xlarge" });
            MvcHtmlString validationMsgHtml = htmlHelper.ValidationMessageFor(valueExpression, null, new { @class = "help-inline" });

            return htmlHelper.Partial("_NameAndInput", new Tuple<MvcHtmlString, MvcHtmlString, MvcHtmlString>(labelHtml, textBoxHtml, validationMsgHtml));
        }

        /// <summary>
        /// Returns HTML markup to show Name and Drop Down List
        /// </summary>
        /// <typeparam name="TModel">Type of the model</typeparam>
        /// <typeparam name="TValue">Type of the value</typeparam>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="name">Name</param>
        /// <param name="valueExpression">The object that contains the properties to render</param>
        /// <param name="selectList">List of values</param>
        /// <param name="optionLabel">Selected value</param>
        /// <param name="htmlAttributes">An object that contains HTML attributes to set for element</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString NameAndDropDownListFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, string name, Expression<Func<TModel, TValue>> valueExpression,
            IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes)
        {
            MvcHtmlString labelHtml = htmlHelper.Label(name);
            MvcHtmlString textBoxHtml = htmlHelper.DropDownListFor(valueExpression, selectList, optionLabel, htmlAttributes);
            MvcHtmlString validationMsgHtml = htmlHelper.ValidationMessageFor(valueExpression, null, new { @class = "help-inline" });

            return htmlHelper.Partial("_NameAndInput", new Tuple<MvcHtmlString, MvcHtmlString, MvcHtmlString>(labelHtml, textBoxHtml, validationMsgHtml));
        }

        /// <summary>
        /// Extends <see cref="ValidationSummary"/> with custom formatting
        /// </summary>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="excludePropertyErrors">True to have the summary display model-level errors only, 
        /// or false to have the summary display all errors.</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString ValidationSummaryEx(this HtmlHelper htmlHelper, bool excludePropertyErrors)
        {
            MvcHtmlString html = htmlHelper.ValidationSummary(excludePropertyErrors);

            if(html != null && html != MvcHtmlString.Empty)
            {
                return htmlHelper.Partial("_ValidationSummary", html);
            }

            return MvcHtmlString.Empty;
        }

        /// <summary>
        /// Extends <see cref="ValidationSummary"/> with custom formatting
        /// </summary>
        /// <param name="htmlHelper">Html helper instance</param>
        /// <param name="excludePropertyErrors">True to have the summary display model-level errors only, 
        /// or false to have the summary display all errors.</param>
        /// <param name="message">Message</param>
        /// <returns>HTML markup</returns>
        public static MvcHtmlString ValidationSummaryEx(this HtmlHelper htmlHelper, bool excludePropertyErrors, string message)
        {
            MvcHtmlString html = htmlHelper.ValidationSummary(excludePropertyErrors, message);

            if (html != null && html != MvcHtmlString.Empty)
            {
                return htmlHelper.Partial("_ValidationSummary", html);
            }

            return MvcHtmlString.Empty;
        }
    }
}